\chapter {Conclusioni}

\section {Analogie fra programmazione a oggetti e compilazione di linguaggi funzionali}
Vediamo ora nel dettaglio in che modo le caratteristiche della programmazione a oggetti come l'\emph{incapsulamento}, l'\emph{eriditariet\`a} e il \emph
{polimorfismo}
possano essere sfruttate per la compilazione di un linguaggio funzionale.
\lstset{language=[Objective]Caml,
      print=true,
      basicstyle=\small\ttfamily,
      mathescape=true}

\subsection {Incapsulamento}
\begin{quotation}
L'\emph{incapsulamento} \`e il meccanismo che associa il codice e i dati 
che questo manipola, e che
tiene entrambi al sicuro da interferenze e usi impropri provenienti 
dall'esterno~\cite{java}.
\end{quotation}
Come abbiamo gi\`a visto nelle sezioni precedenti le funzioni vengono 
mappate con le \emph{chiusure} che a loro volta vengono compilate
come delle classi.
Una classe \`e proprio una struttura dati atta a contenere sia i dati che
i metodi che operano su di essi, implementando quindi il concetto di 
incapsulamento.
Grazie all'incapsulamento inoltre \`e possibile nascondere delle eventuali
funzioni annidate o dei nomi locali presenti all'interno della definizione
di una funzione essendo questi mappati come attributi privati della classe.
\subsection {Ereditariet\`a}
\begin{quotation}
L'\emph{ereditariet\`a} \`e un modo per formare una nuova classe usando una
classe che \`e stata gi\`a definita.
La nuova classe, detta classe \emph{derivata}, eredita gli attributi e il 
comportamento dell'altra classe, detta classe \emph{base}, ma pu\`o aggiungere 
ulteriori caratteristiche e cambiare quelle presenti.
\end{quotation}
Grazie all'ereditariet\`a \`e stato possibile definire all'interno
delle chiusure solo il metodo necessario a saturare l'applicazione
 della funzione,
ereditando i metodi necessari per creare l'applicazione parziale della 
funzione e i metodi per applicare la funzione ad un numero di parametri
maggiore di quelli attesi, dalle classi di supporto runtime.
A loro volta le classi di supporto runtime hanno ereditato dalla classe
\lstinline!Applicable! i metodi necessari per applicare una funzione ai 
suoi parametri, riscrivendo in maniera adeguata ciascun metodo.
Una vista parziale della gerarchia delle classi di supporto 
del programma \`e mostrata in Figura~\ref{fig:type}.

\subsection {Polimorfismo}
\begin{quotation}
Il \emph{polimorfismo} \`e la capacit\`a di oggetti, appartenenti a tipi diversi
della stessa gerarchia delle classi, di poter invocare metodi con lo stesso
nome il cui comportamento differisce dal tipo runtime dell'oggetto.
\end{quotation}
Come abbiamo precedentemente visto nella Tabella~\ref{tab:feval},
la valutazione dell'applicazione di una funzione avviene in
maniera diversa in base all'arit\`a della funzione e al numero
di parametri passati.
Pi\`u precisamente esistono sei comportamenti possibili di applicazione
di una funzione o una funzione specializzata ad un numero di parametri minore,
maggiore o uguale al numero di parametri attesi.
Per questo un linguaggio che non permette il polimorfismo dovrebbe
testare, mediante un'istruzione \lstinline!switch!, quanti sono i
parametri effettivamente passati ad una funzione o ad una funzione
specializzata, per eseguire il comportamento opportuno.
Invece sfruttando il polimorfismo \`e stato possibile invocare su oggetti del
tipo generico \lstinline!Applicable! i metodi che sono stati riscritti nelle
sue classi derivate; lo stesso meccanismo \`e stato usato per
stampare a video il risultato di un programma, grazie al fatto che
il metodo \lstinline!toString()! viene riscritto in ogni classe che
implementa un tipo di dato.
Il metodo che veniva effettivamente invocato dipendeva quindi dal
tipo runtime dell'oggetto e non dal tipo definito nel programma.
Questo meccanismo \`e possibile in quanto il compilatore Java usa
il \emph{late binding} per la risoluzione dei nomi dei metodi che
vengono riscritti nelle classi derivate.

\section{In conclusione}
L'idea di base di questo progetto era verificare se un linguaggio funzionale
potesse essere compilato ``convenientemente'' in un linguaggio a oggetti,
intendendo per ``convenienza'' il grado di naturalezza della compilazione 
ed il grado di efficienza del codice ottenuto.
L'idea era interessante a causa della ``lontananza'' dei due paradigmi 
di programmazione e soprattutto utile in vista di una possibile integrazione
futura di questo progetto nel compilatore del linguaggio 
\textit{Carbon}~\cite{carbon}, che spiegheremo nella prossima sezione.

Come abbiamo visto la compilazione del nostro linguaggio {\flang} nel linguaggio
{\olang} avviene in maniera molto naturale, usando le classi della programmazione a oggetti per mappare le chiusure.
In particolare abbiamo usato il costruttore della classe per inizializzare gli
attributi della classe che rappresentano le variabili libere di una funzione e 
grazie all'ereditariet\`a e al polimorfismo abbiamo ridefinito all'interno
della classe il solo metodo necessario a saturare la funzione, ereditando
i metodi per l'applicazione parziale o per l'applicazione sovrabbondante di
parametri, dalle classi di supporto.
Anche la ricorsione non rappresentava un problema grazie all'uso del 
\lstinline!this! per invocare metodi sull'oggetto corrente.
L'efficienza del codice generato invece non \`e stata testata, ma crediamo che
sia buona vista la naturalezza della compilazione.

Ora vediamo quali possono essere i sviluppi futuro di questo progetto,
riguardanti l'ottimizzazione del codice generato e l'integrazione nel
compilatore del linguaggio Carbon.
 

\section {Sviluppi futuri}
\subsection {Ottimizzazione delle funzioni chiuse}


Una funzione chiusa \`e una funzione che non ha variabili libere nel suo corpo.
Ad esempio la funzione identit\`a:
\begin{ScriptMath}
fun x -> x
\end{ScriptMath}
\`e chiusa in quanto il solo nome che compare nel corpo della funzione \`e il
suo argomento. Invece la seguente funzione:
\begin{ScriptMath}
let a = 3 in
fun x $\to$ x + a
\end{ScriptMath}
non \`e chiusa in quanto il nome $a$ \`e un nome libero nel corpo della funzione.
Una funziona chiusa ha un ambiente vuoto, quindi la chiusura della funzione non
dipende da nessun valore runtime e pu\`o essere allocata staticamente in fase
di compilazione.
Da qui nasce l'idea di poter mappare le funzioni chiuse come metodi statici
di una classe.
Questa intuizione inoltre permette di ottimizzare una pi\`u vasta gamma di 
funzioni: le funzioni semi-chiuse~\cite{carbon}.
Ad esempio la seguente funzione \lstinline!f!:
\begin{ScriptMath}
let f = fun x $\to$ g x
\end{ScriptMath}
prende in input un valore \lstinline!x! e applica \lstinline!g! ad 
\lstinline!x!. Essendo \lstinline!g! un nome libero nel corpo della funzione
\lstinline!f! andrebbe memorizzato nella sua chiusura.
Sapendo per\`o che \lstinline!g! \`e chiusa ed \`e mappata come metodo
statico di una classe non c'\`e bisogno di memorizzarla nella chiusura.
A questo punto, visto che nel corpo di \lstinline!f! non compaiono variabili
libere che devono esssere memorizzate nella sua chiusura si pu\`o mappare
anche \lstinline!f! come metodo statico. Una funzione come \lstinline!f! si 
definisce quindi semi-chiusa. 
Cos\`i facendo si riesce quindi a risparmiare spazio costruendo le chiusure solo
quando \`e strettamente necessario.

\subsection{Integrazione in Carbon}
Dopo aver fatto le dovute valutazioni prestazionali del codice generato 
si potrebbe integrare questo progetto nel compilatore del linguaggio
Carbon.
L'idea di partenza era infatti quello di compilare il linguaggio {\colang}
nella Java Virtual Machine e poi integrare questa conoscenza nel
compilatore di Carbon.
Purtroppo per problemi di tempo si \`e scelto come linguaggio target
Java ma questo progetto pu\`o essere benissimo un punto di partenza per 
una futura compilazione verso la Java Virtual Machine e la sua
integrazione in Carbon. 